package main

import (
    "encoding/hex"
    "fmt"
    "net"
    "time"
)

// 编码数据为 ASCII 码表示的十六进制
func encodeToASCIIHex(data []byte) []byte {
    encoded := make([]byte, hex.EncodedLen(len(data)))
    hex.Encode(encoded, data)
    return encoded
}

// 构建协议帧
func buildProtocolFrame(adr, cid1, cid2 byte, info []byte) ([]byte, error) {
    soi := byte(0x7E)                          // SOI 固定值，直接使用
    ver := byte(0x01)                          // 假设协议版本
    length := uint16(len(info) * 2)            // 实际传输的 ASCII 字节数
    eoi := byte(0x0D)                          // EOI 固定值，直接使用

    // 计算校验和（仅计算 ver, adr, cid1, cid2, length 和 info 部分）
    rawData := []byte{ver, adr, cid1, cid2, byte(length >> 8), byte(length)}
    rawData = append(rawData, info...)
    chksum := calculateChecksum(rawData)

    // 构建帧，转换为 ASCII 表示的十六进制格式
    frame := []byte{soi}
    frame = append(frame, encodeToASCIIHex([]byte{ver, adr, cid1, cid2, byte(length >> 8), byte(length)})...)
    frame = append(frame, encodeToASCIIHex(info)...)
    frame = append(frame, encodeToASCIIHex([]byte{byte(chksum >> 8), byte(chksum & 0xFF)})...)
    frame = append(frame, eoi)

    return frame, nil
}

// 计算 CHKSUM
func calculateChecksum(data []byte) uint16 {
    var sum uint16
    for _, b := range data {
        sum += uint16(b)
    }
    return ^sum + 1
}

// 发送和接收协议帧
func communicateWithSM(conn net.Conn, adr, cid1, cid2 byte, info []byte) error {
    frame, err := buildProtocolFrame(adr, cid1, cid2, info)
    if err != nil {
        return fmt.Errorf("构建协议帧失败: %v", err)
    }

    // 发送协议帧
    _, err = conn.Write(frame)
    if err != nil {
        return fmt.Errorf("发送协议帧失败: %v", err)
    }
    fmt.Println("发送的协议帧:", frame)

    // 设置读取超时并接收响应
    conn.SetReadDeadline(time.Now().Add(2 * time.Second))
    response := make([]byte, 256)
    n, err := conn.Read(response)
    if err != nil {
        return fmt.Errorf("接收响应失败: %v", err)
    }

    fmt.Println("接收到的响应:", response[:n])
    return nil
}

func main2() {
    targetAddr := "192.168.1.100:5020" // 假设设备 IP 和端口

    conn, err := net.Dial("tcp", targetAddr)
    if err != nil {
        fmt.Println("连接失败:", err)
        return
    }
    defer conn.Close()

    adr, cid1, cid2 := byte(0x01), byte(0x10), byte(0x20)
    info := []byte{0x30, 0x40} // 示例信息内容

    if err := communicateWithSM(conn, adr, cid1, cid2, info); err != nil {
        fmt.Println("通信失败:", err)
    }
}
